home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / share / pyshared / gtk-2.0 / dsextras.py
Encoding:
Python Source  |  2010-08-16  |  16.0 KB  |  458 lines

  1. #
  2. # dsextras.py - Extra classes and utilities for distutils, adding
  3. #               pkg-config support
  4.  
  5.  
  6. from distutils.command.build_ext import build_ext
  7. from distutils.command.install_lib import install_lib
  8. from distutils.command.install_data import install_data
  9. from distutils.extension import Extension
  10. import distutils.dep_util
  11. import fnmatch
  12. import os
  13. import re
  14. import string
  15. import sys
  16.  
  17. GLOBAL_INC = []
  18. GLOBAL_MACROS = []
  19.  
  20. def get_m4_define(varname):
  21.     """Return the value of a m4_define variable as set in configure.in."""
  22.     pattern = re.compile("m4_define\(" + varname + "\,\s*(.+)\)")
  23.     if os.path.exists('configure.ac'):
  24.         fname = 'configure.ac'
  25.     elif os.path.exists('configure.in'):
  26.         fname = 'configure.in'
  27.     else:
  28.         raise SystemExit('could not find configure file')
  29.  
  30.     for line in open(fname).readlines():
  31.         match_obj = pattern.match(line)
  32.         if match_obj:
  33.             return match_obj.group(1)
  34.  
  35.     return None
  36.  
  37. def getoutput(cmd):
  38.     """Return output (stdout or stderr) of executing cmd in a shell."""
  39.     return getstatusoutput(cmd)[1]
  40.  
  41. def getstatusoutput(cmd):
  42.     """Return (status, output) of executing cmd in a shell."""
  43.     if sys.platform == 'win32':
  44.         pipe = os.popen(cmd, 'r')
  45.         text = pipe.read()
  46.         sts = pipe.close() or 0
  47.         if text[-1:] == '\n':
  48.             text = text[:-1]
  49.         return sts, text
  50.     else:
  51.         from commands import getstatusoutput
  52.         return getstatusoutput(cmd)
  53.  
  54. def have_pkgconfig():
  55.     """Checks for the existence of pkg-config"""
  56.     if (sys.platform == 'win32' and
  57.         os.system('pkg-config --version > NUL') == 0):
  58.         return 1
  59.     else:
  60.         if getstatusoutput('pkg-config')[0] == 256:
  61.             return 1
  62.  
  63. def list_files(dir):
  64.     """List all files in a dir, with filename match support:
  65.     for example: glade/*.glade will return all files in the glade directory
  66.     that matches *.glade. It also looks up the full path"""
  67.     if dir.find(os.sep) != -1:
  68.         parts = dir.split(os.sep)
  69.         dir = string.join(parts[:-1], os.sep)
  70.         pattern = parts[-1]
  71.     else:
  72.         pattern = dir
  73.         dir = '.'
  74.  
  75.     dir = os.path.abspath(dir)
  76.     retval = []
  77.     for file in os.listdir(dir):
  78.         if fnmatch.fnmatch(file, pattern):
  79.             retval.append(os.path.join(dir, file))
  80.     return retval
  81.  
  82. def pkgc_version_check(name, req_version):
  83.     """Check the existence and version number of a package:
  84.     returns 0 if not installed or too old, 1 otherwise."""
  85.     is_installed = not os.system('pkg-config --exists %s' % name)
  86.     if not is_installed:
  87.         return 0
  88.  
  89.     orig_version = getoutput('pkg-config --modversion %s' % name)
  90.     version = map(int, orig_version.split('.'))
  91.     pkc_version = map(int, req_version.split('.'))
  92.  
  93.     if version >= pkc_version:
  94.         return 1
  95.         
  96.     return 0
  97.  
  98. def pkgc_get_libraries(name):
  99.     """returns a list of libraries as returned by pkg-config --libs-only-l"""
  100.     output = getoutput('pkg-config --libs-only-l %s' % name)
  101.     return output.replace('-l', '').split()
  102.  
  103. def pkgc_get_library_dirs(name):
  104.     """returns a list of library dirs as returned by pkg-config --libs-only-L"""
  105.     output = getoutput('pkg-config --libs-only-L %s' % name)
  106.     return output.replace('-L', '').split()
  107.  
  108. def pkgc_get_include_dirs(name):
  109.     """returns a list of include dirs as returned by pkg-config --cflags-only-I"""
  110.     output = getoutput('pkg-config --cflags-only-I %s' % name)
  111.     return output.replace('-I', '').split()
  112.  
  113. class BuildExt(build_ext):
  114.     def init_extra_compile_args(self):
  115.         self.extra_compile_args = []
  116.         if sys.platform == 'win32' and \
  117.            self.compiler.compiler_type == 'mingw32':
  118.             # MSVC compatible struct packing is required.
  119.             # Note gcc2 uses -fnative-struct while gcc3
  120.             # uses -mms-bitfields. Based on the version
  121.             # the proper flag is used below.
  122.             msnative_struct = { '2' : '-fnative-struct',
  123.                                 '3' : '-mms-bitfields' }
  124.             gcc_version = getoutput('gcc -dumpversion')
  125.             print 'using MinGW GCC version %s with %s option' % \
  126.                   (gcc_version, msnative_struct[gcc_version[0]])
  127.             self.extra_compile_args.append(msnative_struct[gcc_version[0]])
  128.  
  129.     def modify_compiler(self):
  130.         if sys.platform == 'win32' and \
  131.            self.compiler.compiler_type == 'mingw32':
  132.             # Remove '-static' linker option to prevent MinGW ld
  133.             # from trying to link with MSVC import libraries.
  134.             if self.compiler.linker_so.count('-static'):
  135.                 self.compiler.linker_so.remove('-static')
  136.  
  137.     def build_extensions(self):
  138.         # Init self.extra_compile_args
  139.         self.init_extra_compile_args()
  140.         # Modify default compiler settings
  141.         self.modify_compiler()
  142.         # Invoke base build_extensions()
  143.         build_ext.build_extensions(self)
  144.  
  145.     def build_extension(self, ext):
  146.         # Add self.extra_compile_args to ext.extra_compile_args
  147.         ext.extra_compile_args += self.extra_compile_args
  148.         # Generate eventual templates before building
  149.         if hasattr(ext, 'generate'):
  150.             ext.generate()
  151.         # Filter out 'c' and 'm' libs when compilic w/ msvc
  152.         if sys.platform == 'win32' and self.compiler.compiler_type == 'msvc':
  153.             save_libs = ext.libraries
  154.             ext.libraries = [lib for lib in ext.libraries 
  155.                              if lib not in ['c', 'm']]
  156.         else:
  157.             save_libs = ext.libraries
  158.         # Invoke base build_extension()
  159.         build_ext.build_extension(self, ext)
  160.         if save_libs != None and save_libs != ext.libraries:
  161.             ext.libraries = save_libs
  162.  
  163. class InstallLib(install_lib):
  164.  
  165.     local_outputs = []
  166.     local_inputs = []
  167.  
  168.     def set_install_dir(self, install_dir):
  169.         self.install_dir = install_dir
  170.  
  171.     def get_outputs(self):
  172.         return install_lib.get_outputs(self) + self.local_outputs
  173.  
  174.     def get_inputs(self):
  175.         return install_lib.get_inputs(self) + self.local_inputs
  176.  
  177. class InstallData(install_data):
  178.  
  179.     local_outputs = []
  180.     local_inputs = []
  181.     template_options = {}
  182.  
  183.     def prepare(self):
  184.         if os.name == "nt":
  185.             self.prefix = os.sep.join(self.install_dir.split(os.sep)[:-3])
  186.         else:
  187.             # default: os.name == "posix"
  188.             self.prefix = os.sep.join(self.install_dir.split(os.sep)[:-4])
  189.  
  190.         self.exec_prefix = '${prefix}/bin'
  191.         self.includedir = '${prefix}/include'
  192.         self.libdir = '${prefix}/lib'
  193.         self.datarootdir = '${prefix}/share'
  194.         self.datadir = '${prefix}/share'
  195.  
  196.         self.add_template_option('prefix', self.prefix)
  197.         self.add_template_option('exec_prefix', self.exec_prefix)
  198.         self.add_template_option('includedir', self.includedir)
  199.         self.add_template_option('libdir', self.libdir)
  200.         self.add_template_option('datarootdir', self.datarootdir)
  201.         self.add_template_option('datadir', self.datadir)
  202.         self.add_template_option('PYTHON', sys.executable)
  203.         self.add_template_option('THREADING_CFLAGS', '')
  204.  
  205.     def set_install_dir(self, install_dir):
  206.         self.install_dir = install_dir
  207.  
  208.     def add_template_option(self, name, value):
  209.         self.template_options['@%s@' % name] = value
  210.  
  211.     def install_template(self, filename, install_dir):
  212.         """Install template filename into target directory install_dir."""
  213.         output_file = os.path.split(filename)[-1][:-3]
  214.  
  215.         template = open(filename).read()
  216.         for key, value in self.template_options.items():
  217.             template = template.replace(key, value)
  218.  
  219.         output = os.path.join(install_dir, output_file)
  220.         self.mkpath(install_dir)
  221.         open(output, 'w').write(template)
  222.         self.local_inputs.append(filename)
  223.         self.local_outputs.append(output)
  224.         return output
  225.  
  226.     def get_outputs(self):
  227.         return install_data.get_outputs(self) + self.local_outputs
  228.  
  229.     def get_inputs(self):
  230.         return install_data.get_inputs(self) + self.local_inputs
  231.  
  232. class PkgConfigExtension(Extension):
  233.     # Name of pygobject package extension depends on, can be None
  234.     pygobject_pkc = 'pygobject-2.0'
  235.     can_build_ok = None
  236.     def __init__(self, **kwargs):
  237.         name = kwargs['pkc_name']
  238.         if 'include_dirs' in kwargs:
  239.             kwargs['include_dirs'] += self.get_include_dirs(name) + GLOBAL_INC
  240.         else:
  241.             kwargs['include_dirs'] = self.get_include_dirs(name) + GLOBAL_INC
  242.         kwargs['define_macros'] = GLOBAL_MACROS
  243.         if 'libraries' in kwargs:
  244.             kwargs['libraries'] += self.get_libraries(name)
  245.         else:
  246.             kwargs['libraries'] = self.get_libraries(name)
  247.         if 'library_dirs' in kwargs:
  248.             kwargs['library_dirs'] += self.get_library_dirs(name)
  249.         else:
  250.             kwargs['library_dirs'] = self.get_library_dirs(name)
  251.         if 'pygobject_pkc' in kwargs:
  252.             self.pygobject_pkc = kwargs.pop('pygobject_pkc')
  253.         if self.pygobject_pkc:
  254.             kwargs['include_dirs'] += self.get_include_dirs(self.pygobject_pkc)
  255.             kwargs['libraries'] += self.get_libraries(self.pygobject_pkc)
  256.             kwargs['library_dirs'] += self.get_library_dirs(self.pygobject_pkc)
  257.         self.name = kwargs['name']
  258.         self.pkc_name = kwargs['pkc_name']
  259.         self.pkc_version = kwargs['pkc_version']
  260.         del kwargs['pkc_name'], kwargs['pkc_version']
  261.         Extension.__init__(self, **kwargs)
  262.  
  263.     def get_include_dirs(self, names):
  264.         if type(names) != tuple:
  265.             names = (names,)
  266.         retval = []
  267.         for name in names:
  268.             output = getoutput('pkg-config --cflags-only-I %s' % name)
  269.             retval.extend(output.replace('-I', '').split())
  270.         return retval
  271.  
  272.     def get_libraries(self, names):
  273.         if type(names) != tuple:
  274.             names = (names,)
  275.         retval = []
  276.         for name in names:
  277.             output = getoutput('pkg-config --libs-only-l %s' % name)
  278.             retval.extend(output.replace('-l', '').split())
  279.         return retval
  280.  
  281.     def get_library_dirs(self, names):
  282.         if type(names) != tuple:
  283.             names = (names,)
  284.         retval = []
  285.         for name in names:
  286.             output = getoutput('pkg-config --libs-only-L %s' % name)
  287.             retval.extend(output.replace('-L', '').split())
  288.         return retval
  289.  
  290.     def can_build(self):
  291.         """If the pkg-config version found is good enough"""
  292.         if self.can_build_ok != None:
  293.             return self.can_build_ok
  294.  
  295.         if type(self.pkc_name) != tuple:
  296.             reqs = [(self.pkc_name, self.pkc_version)]
  297.         else:
  298.             reqs = zip(self.pkc_name, self.pkc_version)
  299.  
  300.         for package, version in reqs:
  301.             retval = os.system('pkg-config --exists %s' % package)
  302.             if retval:
  303.                 print ("* %s.pc could not be found, bindings for %s"
  304.                        " will not be built." % (package, self.name))
  305.                 self.can_build_ok = 0
  306.                 return 0
  307.  
  308.             orig_version = getoutput('pkg-config --modversion %s' %
  309.                                      package)
  310.             if (map(int, orig_version.split('.')) >=
  311.                 map(int, version.split('.'))):
  312.                 self.can_build_ok = 1
  313.                 return 1
  314.             else:
  315.                 print "Warning: Too old version of %s" % self.pkc_name
  316.                 print "         Need %s, but %s is installed" % \
  317.                       (version, orig_version)
  318.                 self.can_build_ok = 0
  319.                 return 0
  320.  
  321.     def generate(self):
  322.         pass
  323.  
  324. # The Template and TemplateExtension classes require codegen which is
  325. # currently part of the pygtk distribution. While codegen might ultimately
  326. # be moved to pygobject, it was decided (bug #353849) to keep the Template
  327. # and TemplateExtension code in dsextras. In the meantime, we check for the
  328. # availability of codegen and redirect the user to the pygtk installer if
  329. # he/she wants to get access to Template and TemplateExtension.
  330.  
  331. template_classes_enabled=True
  332. codegen_error_message="""
  333. ***************************************************************************
  334. Codegen could not be found on your system and is required by the
  335. dsextras.Template and dsextras.TemplateExtension classes. codegen is part
  336. of PyGTK. To use either Template or TemplateExtension, you should also
  337. install PyGTK.
  338. ***************************************************************************
  339. """
  340. try:
  341.     from codegen.override import Overrides
  342.     from codegen.defsparser import DefsParser
  343.     from codegen.codegen import register_types, SourceWriter, \
  344.          FileOutput
  345.     import codegen.createdefs
  346. except ImportError, e:
  347.     template_classes_enabled=False
  348.  
  349. class Template(object):
  350.     def __new__(cls,*args, **kwds):
  351.         if not template_classes_enabled:
  352.             raise NameError("'%s' is not defined\n" % cls.__name__
  353.                             + codegen_error_message)    
  354.         return object.__new__(cls,*args, **kwds)
  355.  
  356.     def __init__(self, override, output, defs, prefix,
  357.                  register=[], load_types=None, py_ssize_t_clean=False):
  358.         
  359.         self.override = override
  360.         self.output = output
  361.         self.prefix = prefix
  362.         self.load_types = load_types
  363.         self.py_ssize_t_clean = py_ssize_t_clean
  364.  
  365.         self.built_defs=[]
  366.         if isinstance(defs,tuple):
  367.             self.defs=defs[0]
  368.             self.built_defs.append(defs)
  369.         else:
  370.             self.defs=defs
  371.  
  372.         self.register=[]
  373.         for r in register:
  374.             if isinstance(r,tuple):
  375.                 self.register.append(r[0])
  376.                 self.built_defs.append(r)
  377.             else:
  378.                 self.register.append(r)
  379.  
  380.     def check_dates(self):
  381.         # Return True if files are up-to-date
  382.         files=self.register[:]
  383.         files.append(self.override)
  384.         files.append(self.defs)
  385.  
  386.         return not distutils.dep_util.newer_group(files,self.output)
  387.  
  388.     def generate_defs(self):
  389.         for (target,sources) in self.built_defs:
  390.             if distutils.dep_util.newer_group(sources,target):
  391.                 # createdefs is mostly called from the CLI !
  392.                 args=['dummy',target]+sources
  393.                 codegen.createdefs.main(args)
  394.  
  395.  
  396.     def generate(self):
  397.         # Generate defs files if necessary
  398.         self.generate_defs()
  399.         # ... then check the file timestamps
  400.         if self.check_dates():
  401.             return
  402.  
  403.         for item in self.register:
  404.             dp = DefsParser(item,dict(GLOBAL_MACROS))
  405.             dp.startParsing()
  406.             register_types(dp)
  407.  
  408.         if self.load_types:
  409.             globals = {}
  410.             execfile(self.load_types, globals)
  411.  
  412.         dp = DefsParser(self.defs,dict(GLOBAL_MACROS))
  413.         dp.startParsing()
  414.         register_types(dp)
  415.  
  416.         fd = open(self.output, 'w')
  417.         sw = SourceWriter(dp,Overrides(self.override),
  418.                           self.prefix,FileOutput(fd,self.output))
  419.         sw.write(self.py_ssize_t_clean)
  420.         fd.close()
  421.  
  422. class TemplateExtension(PkgConfigExtension):
  423.     def __new__(cls,*args, **kwds):
  424.         if not template_classes_enabled:
  425.             raise NameError("'%s' is not defined\n" % cls.__name__
  426.                             + codegen_error_message)    
  427.         return PkgConfigExtension.__new__(cls,*args, **kwds)
  428.     
  429.     def __init__(self, **kwargs):
  430.         name = kwargs['name']
  431.         defs = kwargs['defs']
  432.         if isinstance(defs,tuple):
  433.             output = defs[0][:-5] + '.c'
  434.         else:
  435.             output = defs[:-5] + '.c'
  436.         override = kwargs['override']
  437.         load_types = kwargs.get('load_types')
  438.         py_ssize_t_clean = kwargs.pop('py_ssize_t_clean',False)
  439.         self.templates = []
  440.         self.templates.append(Template(override, output, defs, 'py' + name,
  441.                                        kwargs['register'], load_types,
  442.                                        py_ssize_t_clean))
  443.  
  444.         del kwargs['register'], kwargs['override'], kwargs['defs']
  445.         if load_types:
  446.             del kwargs['load_types']
  447.  
  448.         if kwargs.has_key('output'):
  449.             kwargs['name'] = kwargs['output']
  450.             del kwargs['output']
  451.  
  452.         PkgConfigExtension.__init__(self, **kwargs)
  453.  
  454.     def generate(self):
  455.         map(lambda x: x.generate(), self.templates)
  456.  
  457.  
  458.